#pragma once 
#include<iostream>
#include<vector>
#include<queue>
#include"Thread.hpp"
#include"LockGuard.hpp"
#include"Log.hpp"
using namespace ThreadModule;
const static int gdefaultthreadnum = 10;
template<typename T>
class ThreadPool
{      
    private:
        int _threadnum;
        std::vector<Thread> _threads;
        std::queue<T> _task_queue;
        pthread_mutex_t _mutex;//互斥锁
        pthread_cond_t _cond;//条件变量

        int _waitnum;
        bool _isruning;
    private:
        //添加单例模式
        static ThreadPool<T>* _instance;
        static pthread_mutex_t _lock;
        //构造私有
        ThreadPool(int threadnum = gdefaultthreadnum)
        :_threadnum(threadnum)
        ,_waitnum(0)
        ,_isruning(false)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_cond,nullptr);
            LOG(DEBUG,"Thread constrcut()");
        }
        //禁止拷贝构造
        ThreadPool<T>& operator=(const ThreadPool<T>& ) = delete;
        ThreadPool(const ThreadPool<T>& ) = delete;
        void LockQueue()
        {
            pthread_mutex_lock(&_mutex);
        }
        void UnlockQueue()
        {
            pthread_mutex_unlock(&_mutex);
        }
        void ThreadSleep()
        {
            pthread_cond_wait(&_cond,&_mutex);
        }
        void ThreadWakeup()
        {
            pthread_cond_signal(&_cond);
        }
        void ThreadWakeupAll()
        {
            pthread_cond_broadcast(&_cond);
        }

        void InitThreadPool()
        {
            //构建出所有线程，并不启动
            for(int i = 0; i < _threadnum; i++)
            {
                std::string name = "Thread-" + std::to_string(i + 1);
                _threads.emplace_back(std::bind(&ThreadPool::HandleTask,this,std::placeholders::_1),name);
                LOG(INFO,"init thread %s done",name.c_str());
                _isruning = true;
            }
        }
        void Start()
        {
            for(auto& it : _threads)
            {
                it.Start();
            }
        }
        void HandleTask(const std::string& name)    
        {
            LOG(INFO,"%s is runing... ",name.c_str());
            while(true)
            {
                //1. 保证队列安全
                LockQueue();
                //2. 队列中不一定有数据
                while(_task_queue.empty() && _isruning)
                {
                    _waitnum++;
                    ThreadSleep();
                    _waitnum--;
                }
                //2.1 当线程池已经退出了 && 任务队列是空的
                if(_task_queue.empty() && !_isruning)
                {
                    UnlockQueue();
                    break;
                }
                //2.2 如果线程池不退出 && 任务队列不为空
                //2.3 如果线程池已经退出 && 任务队列不为空--处理完所有任务后退出
                //2.3 一定有任务，处理任务
                T t = _task_queue.front();
                _task_queue.pop();
                UnlockQueue();
                LOG(INFO,"%s get a task",name.c_str());
                //4. 处理任务属于线程独占的任务
                t();
                // LOG(DEBUG,"%s handler a task, result is: %s",name.c_str(),t.ResultToString().c_str());
            }
        }
    public:

        static ThreadPool<T>* Get_instance()
        {
            // 如果是多线程获取线程池对象下面的代码就有问题了！！
            // 只有第一次会创建对象，后续都是获取
            // 双判断的方式，可以有效减少获取单例的加锁成本，而且保证线程安全
            if(nullptr == _instance) //第一次没有加锁 当创建单例后直接返回
            {
                LockGuard lockguard(&_lock);
                if(nullptr == _instance)
                {
                    _instance = new ThreadPool<T>();
                    _instance->InitThreadPool();
                    _instance->Start();
                    LOG(INFO,"创建线程池单例");
                    return _instance;
                }
            }
            LOG(DEBUG,"获取线程单例");
            return _instance;
        }
        void Stop()
        {
            LockQueue();
            _isruning = false;
            ThreadWakeupAll();
            UnlockQueue();
        }   
        void Wait()
        {
            for(auto thread : _threads)
            {
                thread.Join();
                LOG(INFO,"%s is quit ...", thread.Name().c_str());
            }
        }
        bool Enqueue(const T& t)
        {
            bool ret = false;
            LockQueue();
            if(_isruning)
            {
                _task_queue.push(t);
                if(_waitnum > 0)
                {
                    ThreadWakeup();
                }
                LOG(DEBUG,"enqueue task success");
                ret = true;
            }
            UnlockQueue();
            return ret;
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }
      
};
template<typename T>
ThreadPool<T>* ThreadPool<T>::_instance = nullptr;
template<typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;
